<template>
  <div class="process-viewer">
    <div class="process-canvas" style="height: 100%;" ref="processCanvas" v-show="!isLoading" />
    <!-- 自定义箭头样式，用于成功状态下流程连线箭头 -->
    <defs ref="customSuccessDefs">
      <marker id="sequenceflow-end-white-success" viewBox="0 0 20 20" refX="11" refY="10" markerWidth="10" markerHeight="10" orient="auto">
        <path class="success-arrow" d="M 1 5 L 11 10 L 1 15 Z" style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;"></path>
      </marker>
      <marker id="conditional-flow-marker-white-success" viewBox="0 0 20 20" refX="-1" refY="10" markerWidth="10" markerHeight="10" orient="auto">
        <path class="success-conditional" d="M 0 10 L 8 6 L 16 10 L 8 14 Z" style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;"></path>
      </marker>
    </defs>
    <!-- 自定义箭头样式，用于失败状态下流程连线箭头 -->
    <defs ref="customFailDefs">
      <marker id="sequenceflow-end-white-fail" viewBox="0 0 20 20" refX="11" refY="10" markerWidth="10" markerHeight="10" orient="auto">
        <path class="fail-arrow" d="M 1 5 L 11 10 L 1 15 Z" style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;"></path>
      </marker>
      <marker id="conditional-flow-marker-white-fail" viewBox="0 0 20 20" refX="-1" refY="10" markerWidth="10" markerHeight="10" orient="auto">
        <path class="fail-conditional" d="M 0 10 L 8 6 L 16 10 L 8 14 Z" style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;"></path>
      </marker>
    </defs>
    <!-- 已完成节点悬浮弹窗 -->
    <el-dialog class="comment-dialog" :title="dlgTitle || '审批记录'" v-model="dialogVisible">
      <el-row>
        <el-table :data="taskCommentList" border header-cell-class-name="table-header-gray">
          <el-table-column label="序号" header-align="center" align="center" type="index" width="55px" />
          <el-table-column label="候选办理" prop="candidate" width="150px" align="center"/>
          <el-table-column label="实际办理" prop="assigneeName" width="100px" align="center"/>
          <el-table-column label="处理时间" prop="createTime" width="140px" align="center"/>
          <el-table-column label="办结时间" prop="finishTime" width="140px" align="center" />
          <el-table-column label="耗时" prop="duration" width="100px" align="center"/>
          <el-table-column label="审批意见" align="center">
            <template #default="scope">
              {{scope.row.commentList&&scope.row.commentList[0]?scope.row.commentList[0].fullMessage:''}}
            </template>
          </el-table-column>
        </el-table>
      </el-row>
    </el-dialog>
    <div style="position: absolute; top: 0px; left: 0px; width: 100%;">
      <el-row type="flex" justify="end">
        <el-button-group key="scale-control" size="default">
          <el-button size="default" type="default" :plain="true" :disabled="defaultZoom <= 0.3" icon="ZoomOut" @click="processZoomOut()" />
          <el-button size="default" type="default" style="width: 90px;">{{ Math.floor(state.defaultZoom * 10 * 10) + "%" }}</el-button>
          <el-button size="default" type="default" :plain="true" :disabled="defaultZoom >= 3.9" icon="ZoomIn" @click="processZoomIn()" />
          <el-button size="default" type="default" icon="ScaleToOriginal" @click="processReZoom()" />
          <slot />
        </el-button-group>
      </el-row>
    </div>
  </div>
</template>

<script setup>
import '@/plugins/package/theme/index.scss';
import BpmnViewer from 'bpmn-js/lib/Viewer';
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';

const {proxy} = getCurrentInstance()

const props = defineProps({
  xml: {
    type: String
  },
  finishedInfo: {
    type: Object
  },
  // 所有节点审批记录
  allCommentList: {
    type: Array
  }
})
const state = reactive({
  dialogVisible: false,
  dlgTitle: undefined,
  defaultZoom: 1,
  // 是否正在加载流程图
  isLoading: false,
  bpmnViewer: undefined,
  // 已完成流程元素
  processNodeInfo: undefined,
  // 当前任务id
  selectTaskId: undefined,
  // 任务节点审批记录
  taskCommentList: [],
  // 已完成任务悬浮延迟Timer
  hoverTimer: null
})
const {dialogVisible,dlgTitle,defaultZoom,isLoading,bpmnViewer,
  processNodeInfo,selectTaskId,taskCommentList,hoverTimer} = toRefs(state)

watch(()=>props.xml,(newXml)=>{
  importXML(newXml)
})
watch(()=>props.finishedInfo,(newInfo) => {
  setProcessStatus(newInfo);
})

// 显示流程图
async function importXML(xml) {
  clearViewer();
  if (xml != null && xml !== '') {
    try {
      state.bpmnViewer = new BpmnViewer({
        additionalModules: [
          // 移动整个画布
          MoveCanvasModule
        ],
        container: proxy.$refs.processCanvas,
      });
      // 任务节点悬浮事件
      state.bpmnViewer.on('element.click', ({ element }) => {
        // onSelectElement(element);
      });

      state.isLoading = true;
      await state.bpmnViewer.importXML(xml);
      addCustomDefs();
    } catch (e) {
      clearViewer();
    } finally {
      state.isLoading = false;
      setProcessStatus(state.processNodeInfo);
    }
  }
}
// 流程图预览清空
function clearViewer() {
  if (proxy.$refs.processCanvas) {
    proxy.$refs.processCanvas.innerHTML = '';
  }
  if (state.bpmnViewer) {
    state.bpmnViewer.destroy();
  }
  state.bpmnViewer = null;
}
// 任务悬浮弹窗
function onSelectElement(element) {
  state.selectTaskId = undefined;
  state.dlgTitle = undefined;

  if (state.processNodeInfo == null || state.processNodeInfo.finishedTaskSet == null) return;

  if (element == null || state.processNodeInfo.finishedTaskSet.indexOf(element.id) === -1) {
    return;
  }

  state.selectTaskId = element.id;
  state.dlgTitle = element.businessObject ? element.businessObject.name : undefined;
  // 计算当前悬浮任务审批记录，如果记录为空不显示弹窗
  state.taskCommentList = (state.allCommentList || []).filter(item => {
    return item.activityId === state.selectTaskId;
  });
  state.dialogVisible = true;
}
// 添加自定义箭头
function addCustomDefs() {
  const canvas = state.bpmnViewer.get('canvas');
  const svg = canvas._svg;
  const customSuccessDefs = proxy.$refs.customSuccessDefs;
  const customFailDefs = proxy.$refs.customFailDefs;
  svg.appendChild(customSuccessDefs);
  svg.appendChild(customFailDefs);
}
// 设置流程图元素状态
function setProcessStatus (processNodeInfo) {
  state.processNodeInfo = processNodeInfo;
  if (state.isLoading || state.processNodeInfo == null || state.bpmnViewer == null) return;
  let { finishedTaskSet, rejectedTaskSet, unfinishedTaskSet, finishedSequenceFlowSet } = state.processNodeInfo;
  const canvas = state.bpmnViewer.get('canvas');
  const elementRegistry = state.bpmnViewer.get('elementRegistry');
  if (Array.isArray(finishedSequenceFlowSet)) {
    finishedSequenceFlowSet.forEach(item => {
      if (item != null) {
        canvas.addMarker(item, 'success');
        let element = elementRegistry.get(item);
        const conditionExpression = element.businessObject.conditionExpression;
        if (conditionExpression) {
          canvas.addMarker(item, 'condition-expression');
        }
      }
    });
  }
  if (Array.isArray(finishedTaskSet)) {
    finishedTaskSet.forEach(item => canvas.addMarker(item, 'success'));
  }
  if (Array.isArray(unfinishedTaskSet)) {
    unfinishedTaskSet.forEach(item => canvas.addMarker(item, 'primary'));
  }
  if (Array.isArray(rejectedTaskSet)) {
    rejectedTaskSet.forEach(item => {
      if (item != null) {
        let element = elementRegistry.get(item);
        if (element.type.includes('Task')) {
          canvas.addMarker(item, 'danger');
        } else {
          canvas.addMarker(item, 'warning');
        }
      }
    })
  }
}
function getOperationTagType(type) {
  return 'success';
}
function processReZoom() {
  state.defaultZoom = 1;
  state.bpmnViewer.get('canvas').zoom('fit-viewport', 'auto');
}
function processZoomIn(zoomStep = 0.1) {
  let newZoom = Math.floor(state.defaultZoom * 100 + zoomStep * 100) / 100;
  if (newZoom > 4) {
    throw new Error('[Process Designer Warn ]: The zoom ratio cannot be greater than 4');
  }
  state.defaultZoom = newZoom;
  state.bpmnViewer.get('canvas').zoom(state.defaultZoom);
}
function processZoomOut(zoomStep = 0.1) {
  let newZoom = Math.floor(state.defaultZoom * 100 - zoomStep * 100) / 100;
  if (newZoom < 0.2) {
    throw new Error('[Process Designer Warn ]: The zoom ratio cannot be less than 0.2');
  }
  state.defaultZoom = newZoom;
  state.bpmnViewer.get('canvas').zoom(state.defaultZoom);
}
onMounted(() => {
  proxy.$nextTick(() => {
    importXML(props.xml)
    setProcessStatus(props.finishedInfo);
  })
})
onUnmounted(() => {
  clearViewer();
})

</script>

<style scoped>
</style>
